<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>CandyJs js DOC</title>
    <meta name="keywords" content="CandyJs MVC Framework Restful API">
    <meta name="description" content="An object-oriented efficient node.js MVC and REST framework">

    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" >
    <style>
    blockquote {font-size: 14px;}
    blockquote.bg-danger {
        border-left-color: #cc3322;
    }
    blockquote.bg-info {
        border-left-color: #1b809e;
    }
    footer {
        background-color: #222;
        color: #fff;
        padding: 20px 0;
    }
    code {margin: 0 6px;}
    </style>
</head>
<body>
<header>
    <nav class="navbar navbar-inverse">
        <div class="container">
            <a target="_blank" class="navbar-brand" href="https://github.com/douyu-beijing/candyjs">CandyJs</a>
        </div>
    </nav>
</header>

<div class="container" style="margin-top: 60px">
    <div class="row">
        <div class="col-md-9">
<h1>
An object-oriented efficient MVC and REST framework
</h1>

            <h1 class="page-header">Getting started</h1>

            <h4><b>Install the program</b></h4>
            <p>
                <pre><code>npm install candyjs</code></pre>
            </p>

            <h1 class="page-header" id="firstrun"><b>Run the program for the first time</b></h1>
            <p>This example outputs a Hello word program</p>
            <p>First need to create a basic application framework as follows</p>
            <p>In<code>CandyJs</code>the<code>bin</code>directory provides a tool for creating the application<code>_candy</code></p>
            <p>
                <pre><code>./node_modules/.bin/_candy</code></pre>
            </p>

            <p>This will create a simple application as follows</p>
<p>
    <pre><code>
PROJECT_NAME
|
|- index.js
|
|- app
|  |
|  |-- controllers
|      |
|      |-- index
|      |   |
|      |   |-- IndexController.js
|      |
|   -- views
|      |
|      |-- index
|      |   |
|      |   |-- index.html
    </code></pre>
</p>

            <p>Go to the application directory to start the program</p>
            <p><pre><code>node index.js</code></pre></p>
            <p>Access</p>
            <p><pre><code><a href="http://localhost:2333" target="_blank">http://localhost:2333</a></code></pre></p>

            <h1 class="page-header" id="appstruct">Application structure</h1>

            <h4><b>An application directory structure is as follows</b></h4>
<p>
<pre><code>
PROJECT_NAME
|
|- index.js
|
|- node_modules
|
|- public
|
|- app
|  |
|  |-- controllers
|      |
|      |-- user
|      |   |
|      |   |-- IndexController.js
|      |   |-- OtherController.js
|      |
|      |-- goods
|      |   |
|      |   |-- IndexController.js
|      |   |-- OtherController.js
|      |
|   -- views
|      |
|      |-- user
|      |   |
|      |   |-- index.html
|      |   |-- other.html
|      |
|   -- goods
|      |   |
|      |   |-- index.html
|      |   |-- other.html
|      |
|   -- modules
|      |
|      |-- reg
|      |   |
|      |   |-- controllers
|      |   |   |
|      |   |   |-- IndexController.js
|      |   |
|      |   |-- views
|      |   |   |
|      |   |   |-- index.html
|      |   |
|      |   |-- other dir
|      |
|   -- runtime
|
</pre></code>
</p>

            <h4><b>Entry script<code>index.js</code></b></h4>
            <p>
                The entry script is the first loop in the application startup process.
                There is only one entry script that contains the startup script that will listen to the client's connection
            </p>
            <p>
                The entry script basically does the following
                <ul>
                    <li>Load the application configuration</li>
                    <li>Start the application</li>
                    <li>Register all the required components</li>
                </ul>
            </p>
<p>
<pre><code>
var CandyJs = require('candyjs');
var App = require('candyjs/web/Application');

new CandyJs(new App({
    'id': 1,

    'debug': true,

    // application path
    'appPath': __dirname + '/app',

    // register modules
    'modules': {
        'bbs': 'app/modules/bbs'
    },

    // log setting
    'log': {
        'targets': {
            'file': {
                'classPath': 'candy/log/file/Target'
            }
        }
    }

})).listen(2333, function(){
    console.log('listen on 2333');
});
</pre></code>
</p>

            <h4><b>Application</b></h4>
            <p>
                Applications are objects that govern the overall structure and lifecycle of<code>CandyJs</code>application systems.
                Usually a framework contains two applications the<code>Web Application</code>and the<code>Console Application</code>but<code>CandyJs</code>only has a<code>Web Application</code>
            </p>

            <h4><b>Application properties</b></h4>
            <p>
                Various parameters can be introduced in the entry file.
                These parameters will eventually be assigned to the application object
            </p>

            <h6><b>Required properties</b></h6>
            <ul>
                <li>
                    <p><code>candy/web/Application.id</code>This property is used to identify the only application</p>
                </li>
                <li>
                    <p><code>candy/web/Application.appPath</code>This property used to specified application directory</p>
                </li>
            </ul>

            <h6><b>Important attributes</b></h6>
            <ul>
                <li>
                    <p><code>candy/web/Application.routesMap</code>Used to define the routing handler</p>
<p>
<pre><code>
'account': {
    'classPath': 'app/controllers/user/IndexController',
    'property': 'value'
}
</code></pre>
</p>
                </li>
                <li>
                    <p><code>candy/web/Application.modules</code>To register application module</p>
<p>
<pre><code>
// register a bbs module
'modules': {
    'bbs': 'app/modules/bbs'
}
</code></pre>
</p>
                </li>
                <li>
                    <p><code>candy/web/Application.encoding</code>Project encoding</p>
                </li>
                <li>
                    <p><code>candy/web/Application.debug</code>Whether debugging is on</p>
                </li>
            </ul>

            <h4><b>Custom properties</b></h4>
            <p>Other parameters passed in the entry file are passed to the application as a custom parameter</p>

            <h1 class="page-header" id="controller"><b>Application controller</b></h1>
            <p>The controller is part of the<code>MVC</code>schema that inherits the object of<code>candy/core/Controller</code>class responsible for handling the request and generating the response</p>

            <h4><b>Action</b></h4>
            <p>
                The controller consists of<code>actions</code>that is the most basic unit for executing the end user's request.
                A controller has and only one entry action is called<code>run</code>
            </p>
<p>
<pre><code>
'use strict';

var CandyJs = require('candyjs');
var Candy = require('candyjs/Candy');
var Controller = Candy.include('candy/web/Controller');

class IndexController extends Controller {

    run(req, res) {
        res.end('hello');
    }

}

module.exports = IndexController;
</pre></code>
</p>

            <h4><b>Action aspect</b></h4>
            <p>
                If the controller inherits from<code>candy/web/Controller</code>
                Then you can use the action aspect in the controller before or after action to perform some business logic
            </p>
<p>
<pre><code>
'use strict';

var Candy = require('candyjs/Candy');
var Controller = Candy.include('candy/web/Controller');

class IndexController extends Controller {

    beforeAction(actionEvent) {
        console.log('beforeActionCall')
    }

    afterAction(actionEvent) {
        console.log('afterActionCall')
    }

    run(req, res) {
        res.end('hello');
    }

}

module.exports = IndexController;
</pre></code>
</p>

            <blockquote class="bg-danger">
                Note that there may be asynchronous operations in the project code.
                <code>afterActionCall()</code>does not guarantee execution after run() execution is complete
            </blockquote>

            <h1 class="page-header" id="routers">Routers</h1>
            <p>Generally a route corresponds to a controller, there are two kinds of routers</p>
            <ol>
                <li><p><code>route_prefix[/controllerId]</code></p></li>
                <li><p><code>moduleId[/controllerId]</code></p></li>
            </ol>
            <ul>
                <li>
                    <p>when visit <a>http://localhost/</a></p>
                    <p><code>app/controllers/index/IndexControlelr</code> will be created</p>
                </li>
                <li>
                    <p>when visit <a>http://localhost/user</a></p>
                    <p><code>user</code> module will be searched first</p>
                    <p>if found the module, then <code>app/modules/user/controllers/IndexController</code> will be created</p>
                    <p>if not found，then <code>app/controllers/user/IndexController</code> will be created</p>
                </li>
                <li>
                    <p>when visit <a>http://localhost/user/profile</a></p>
                    <p><code>user</code> module will be searched first</p>
                    <p>if found, then <code>app/modules/user/controllers/ProfileController</code> will be created</p>
                    <p>if not, then <code>app/controllers/user/ProfileController</code> will be created</p>
                </li>
                <li>
                    <p>when visit <a>http://localhost/user/profile/settings</a></p>
                    <p><code>user</code> module will be searched first</p>
                    <p>if found then <code>app/modules/user/controllers/SettingsController</code> will be created</p>
                    <p>if not, then <code>app/controllers/user/profile/SettingsController</code> will be created</p>
                </li>
            </ul>

            <p>Controller search order<code>module controller --> common controller</code></p>

            <h1 class="page-header" id="model"><b>Model</b></h1>
            <p>The model is part of the<code>MVC</code>pattern that represents the object of the business data</p>
            <blockquote class="bg-info">
                <p>demo <a target="_blank" href="https://github.com/douyu-beijing/candyjs-examples/tree/master/model">see here for detail</a></p>
            </blockquote>

            <h1 class="page-header" id="view"><b>视图</b></h1>
            <p>视图是<code>MVC</code>模式中的一部分 它用于给终端用户展示页面</p>

            <h4><b>模板引擎</b></h4>
            <blockquote class="bg-info">
                <code>CandyJs</code>提供了<code>@candyjs/template-hbs</code>来负责模板渲染，<a target="_blank" href="https://github.com/douyu-beijing/candyjs-template-hbs">查看详情</a>
            </blockquote>

            <h4><b>其他方式使用模板引擎</b></h4>
            <p>得益于<code>CandyJs</code>灵活的架构设计，使得模板引擎使用非常便捷，这里有如下几种方式：</p>
            <ul>
                <li>全局配置方式</li>
                <li>局部注入方式</li>
                <li>嵌入式</li>
            </ul>
            <p>下面将使用<code>Handlebars</code>对以上方式进行逐个讲解</p>

            <h6><b>全局配置方式</b></h6>
<p>
<pre><code>
// 全局配置方式是使用 candyjs 的别名系统实现的
// 这里的代码可以从源代码 examples 目录中找到

// 1. 在 app/libs 目录中建立一个模板引擎文件 CandyTemplate.js
const fs = require('fs');
const Handlebars = require('handlebars');
// 加载系统视图类
const View = require('candyjs/web/View');

class CandyTemplate extends View {
    constructor(context) {
        super(context);
        this.handlebars = Handlebars.create();
    }

    // 模板引擎必须实现这个方法，因为它是渲染模板的入口
    renderFile(file, parameters) {
        fs.readFile(file, 'UTF-8', (err, template) => {
            let compiled = this.handlebars.compile(template);
            this.context.response.end( compiled(parameters) );
        });
    }
}
module.exports = CandyTemplate;

// 2. 经过第 1 步，我们的模板引擎就开发完了，是不是很简单
// 接下来在入口注册我们编写的模板引擎
const App = require('candyjs/web/Application');
const app = new App({
    'id': 'template_test',

    // 配置模板引擎
    'defaultView': 'app/libs/CandyTemplate',

    'appPath': __dirname + '/app'
});
new CandyJs(app).listen(2333, function(){
    console.log('listen on 2333');
});

// 3. 准备模板 html
&lt;html>
&lt;body>
&lt;ul>
{{#each list}}
    &lt;li>&lt;a href="/user?uid={{ id }}">{{ name }}&lt;/a>&lt;/li>
{{/each}}
&lt;/ul>
&lt;/body>
&lt;/html>

// 4. 在控制器中使用模板引擎渲染页面
const Controller = require('candyjs/web/Controller');
const User = require('somepath/models/User');

class IndexController extends Controller {
    run(req, res) {
        this.fetchList(res);
    }

    async fetchList(res) {
        const user = new User();
        // 这里 data 是一个用户数组 [{id: xxx, name: xxx}]
        let data = await user.getUserList();

        // 可以获取到模板引擎实例
        // 具体使用方式请参考 handlebars 模板引擎官方文档
        // const handlebars = this.getView().handlebars;
        // handlebars.todo

        // 这里的 render 将使用我们制定的模板引擎渲染页面
        this.render('index', {
            list: data
        });
    }
}
</code></pre>
</p>

            <h6><b>局部注入方式</b></h6>
<p>
<pre><code>
// 1. 局部注入方式第 1 步也需要编写我们的模板引擎，参考全局配置方式

// 2. 在控制器中动态注入模板引擎
const Controller = require('candyjs/web/Controller');
const User = require('somepath/models/User');
const CandyTemplate = require('somepath/CandyTemplate');

class IndexController extends Controller {
    run(req, res) {
        this.fetchList(res);
    }

    async fetchList(res) {
        const user = new User();
        let data = await user.getUserList();

        // 动态注入模板引擎
        this.setView(new CandyTemplate(this.context));
        this.render('index', {
            list: data
        });
    }
}

module.exports = IndexController;
</code></pre>
</p>

            <h6><b>嵌入式</b></h6>
<p>
<pre><code>
// 这种方式比较灵活，不需要编写模板引擎

const Controller = require('candyjs/web/Controller');
const Handlebars = require('handlebars');
const User = require('somepath/models/User');

class IndexController extends Controller {
    run(req, res) {
        this.fetchList(res);
    }

    async fetchList(res) {
        const user = new User();
        let data = await user.getUserList();

        this.getView().getTemplateContent('index', (err, str) => {
            // 直接使用模板引擎对内容进行编译并输出
            let compiled = Handlebars.compile(str);

            res.end( compiled({ list: data }) );
        });
    }
}
module.exports = IndexController;
</code></pre>
</p>

            <h4><b>Controller level view API</b></h4>
            <p>
                If the user's controller inherits from the<code>candy/web/Controller</code>
                then can use the<code>getView()</code>method in the controller to get the view class instance
            </p>
            <p>The view class provides the following API for user to use</p>
            <ul>
                <li><code>findViewFile(view)</code>Used to get absolute path of a view file</li>
                <li><code>getTemplateContent(view, callback)</code>Used to read the content of a view file</li>
            </ul>
<p>
<pre><code>
'use strict';

var Candy = require('candyjs/Candy');
var Controller = Candy.include('candy/web/Controller');

class IndexController extends Controller {

    run(req, res) {
        this.getView().getTemplateContent('index', (err, str) => {
            res.end(str);
        });
    }

}

module.exports = IndexController;
</code></pre>
</p>

            <h1 class="page-header" id="module"><b>Module</b></h1>
            <p>
                Module is independent software unit.
                It consists of<code>Model View Controller</code>and other necessary components
            </p>
            <blockquote class="bg-info">
                Note that unlike the common project directory, the controllers and views in the module do not have a subdirectory
            </blockquote>

            <h4><b>Create a module</b></h4>
            <p>In the<code>modules</code>directory create a separate directory eg. bbs</p>
<p>
<pre><code>
modules
    |
    |-- bbs
    |   |
    |   |-- controllers
    |   |   |
    |   |   |-- IndexController.js
    |   |
    |   |-- views
    |   |   |
    |   |   |-- index.html
    |   |
    |   |-- other directory
</code></pre>
</p>

            <h4><b>Register the module</b></h4>
            <p>The module created can not be recognized by the system, we need to manually register</p>
<p>
<pre><code>
var CandyJs = require('candyjs');
var App = require('candyjs/web/Application');

new CandyJs(new App({
    ...

    // register module bbs
    'modules': {
        'bbs': 'app/modules/bbs'
    },

    ...

})).listen(2333, function(){
    console.log('listen on 2333');
});
</code></pre>
</p>

            <h1 class="page-header" id="component"><b>Component & Behavior</b></h1>

            <h4><b>Component</b></h4>
            <p>Component is the base class of<code>Property Behavior and Event</code></p>
            <p>Components are instances of<code>candy/core/Controller</code>, or an extended class</p>
            <p>Behavior classes are typically used in conjunction with component classes</p>

            <h4><b>Behavior</b></h4>
            <p>Behavior is instances of<code>candy/core/Behavior</code>, or an extended class</p>
            <p>A behavior class can be used to enhance its functionality without changing the original component code</p>
            <p>When a behavior is attached to a component, it will inject its methods and properties into the component and then access them as if they were to access the component's own methods and properties</p>
            <p>The behavior class also can listen to the component's events and respond</p>

            <h4><b>Properties</b></h4>
            <p>Membership variables for the javascript class are also known as properties</p>

            <h4><b>Event</b></h4>
            <p><code>CandyJs</code>implements an observer pattern</p>
<p>
<pre><code>
'use strict';

var Candy = require('candyjs/Candy');
var Controller = Candy.include('candy/web/Controller');

class IndexController extends Controller {

    constructor(context) {
        super(context);

        this.on('myevent', function() {
            console.log('myevent fired');
        });
    }

    run(req, res) {
        this.trigger('myevent');

        res.end('hello');
    }

}

module.exports = IndexController;
</code></pre>
</p>

            <h4><b>Use behavior</b></h4>

            <h6><b>Define behavior</b></h6>
            <p>Create a class by inheriting<code>candy/core/Behavior</code>or its subclasses</p>
<p>
<pre><code>
'use strict';

var Candy = require('candyjs/Candy');
var Behavior = Candy.include('candy/core/Behavior');

// 行为类
class MyBehavior extends Behavior {
    constructor() {
        super();
    }

    // 监听控制器的 customEvent 事件
    // 由于一个事件可以有多个处理程序 为保证顺序 这里必须使用数组
    // 格式为 [行为名, 行为处理器]
    events() {
        return [
            ['customEvent', (e) => {
                e.result = 'data processed by behavior';
            }],
            ['customEvent2', (e) => {
                e.result += '--process2';
            }]
        ];
    }
}

module.exports = MyBehavior;
</code></pre>
</p>

            <p>The above code defines the behavior class<code>MyBehavior</code>and provides two properties<code>prop1 prop2</code>and a method for the component to attach the behavior<code>myFun()</code></p>

            <h6><b>Attach behavior to component</b></h6>
            <p>You can attach a behavior to a component either statically or dynamically</p>

            <p>To attach a behavior statically, override the<code>behaviors()</code>method of the component class to which the behavior is being attached</p>
            <p>The<code>behaviors()</code>method should return a list of behavior configurations</p>
<p>
<pre><code>
'use strict';

var Candy = require('candyjs/Candy');
var Controller = Candy.include('candy/web/Controller');

class IndexController extends Controller {

    // 重写方法
    behaviors() {
        return [
            ['myBehavior', new MyBehavior()]
        ];
    }

    run(req, res) {
        let data = {result: ''};
        this.trigger('customEvent', data);

        // 卸载行为
        this.detachBehavior('myBehavior');
        return data.result;
    }

}

module.exports = IndexController;
</code></pre>
</p>

            <p>To attach a behavior dynamically, call the<code>attachBehavior()</code>method of the component to which the behavior is being attached</p>
<p>
<pre><code>
'use strict';

var Candy = require('candyjs/Candy');
var Controller = Candy.include('candy/web/Controller');

class IndexController extends Controller {

    constructor(context) {
        super(context);

        // 动态附加行为 行为里面会监听 customEvent 事件
        this.attachBehavior('myBehavior', new MyBehavior());
    }

    run(req, res) {
        let data = {result: ''};
        this.trigger('customEvent', data);
        this.trigger('customEvent2', data);

        this.detachBehavior('myBehavior');
        return data.result;
    }

}

module.exports = IndexController;
</code></pre>
</p>
            

            <h1 class="page-header" id="midware"><b>Middleware</b></h1>
            <p>The middleware is the first part of the request to process the request and do the filtering and call the next middleware</p>
            <blockquote class="bg-info">
                <code>CandyJs</code>temporarily only provides a middleware for handling static resources
            </blockquote>

            <h1 class="page-header" id="static"><b>Static resource</b></h1>
            <p>
                <code>CandyJs</code>defaults to non-processing of static resources that require the use of middleware
            </p>
<p>
<pre><code>
var CandyJs = require('candyjs');
var Candy = require('candyjs/Candy');
var App = require('candyjs/web/Application');

var Hook = Candy.include('candy/core/Hook');
var R = Candy.include('candy/midwares/Resource');

// serve the public dir as static resources
Hook.addHook(new R(__dirname + '/public').serve());

new CandyJs(new App({

    ...

})).listen(2333, function(){
    console.log('listen on 2333');
});

// in view file, we can use static resource like this: /public/js/lib.js
&lt;script src="/js/lib.js">&lt;/script>
</code></pre>
</p>

            <h1 class="page-header" id="url"><b>URI & URL</b></h1>
            <p>
                <code>candy/web/URI and candy/web/URL</code>classes provide methods for uri and url operations
            </p>

            <h4><b>candy/web/URI</b></h4>
            <ul>
                <li><code>parseUrl()</code>Used for parse url</li>
            </ul>
<p>
<pre><code>
var URI = Candy.include('candy/web/URI');

var uri = new URI();

/*
{
    source: 'http://xxx.com:8080/abc?q=1#anchor',
    scheme: 'http',
    user: undefined,
    password: undefined,
    host: 'xxx.com',
    port: '8080',
    path: '/abc',
    query: 'q=1',
    fragment: 'anchor'
}
*/
uri.parseUrl('http://xxx.com:8080/abc?q=1#anchor');
</code></pre>
</p>

            <h4><b>candy/web/URL</b></h4>
            <ul>
                <li><code>getReferer()</code>Used to get the referer url</li>
                <li><code>getHostInfo()</code>Used to get the host section of URI</li>
                <li><code>getCurrent()</code>Used to get the current URL</li>
                <li><code>to(url[, params = null])</code>Used to create a url</li>
            </ul>
<p>
<pre><code>
var URL = Candy.include('candy/web/URL');

var url = new URL(req);

// return scheme://host/index/index
url.to('index/index');

// return scheme://host/index/index?id=1#anchor
url.to('index/index', {id: 1, '#': 'anchor'})
</code></pre>
</p>

            <h1 class="page-header" id="reqres"><b>Request and Response</b></h1>
            <p>
                <code>CandyJs</code>provides classes<code>candy/http/Request</code>and<code>candy/http/Response</code>that handle requests and responses
            </p>

            <h4><b>HTTP Request</b></h4>
            <p>Used to handle http requests</p>
            <p>
                <code>candy/http/Request</code>class provides a set of instances and static methods to manipulate the required data
            </p>
            <ul>
                <li><code>getQueryString(param)</code>Instance method get the request parameter</li>
                <li><code>getParameter(param)</code>Instance method get the POST request parameter</li>
                <li><code>getCookie(name)</code>Instance method get cookies</li>
                <li><code>getHeaders()</code>Get http headers</li>
            </ul>
            <blockquote class="bg-danger">
                In the use of<code>getParameter()</code>to obtain the POST parameter temporarily need to rely on third-party analysis of the body of the middleware will otherwise back to the null
            </blockquote>
<p>
<pre><code>
var Request = Candy.include('candy/http/Request');
var request = new Request(req);
var id = request.getQueryString('id');
...
</code></pre>
</p>

            <h4><b>HTTP Response</b></h4>
            <p>Outputs a response message to the client</p>
            <p>
                <code>candy/http/Response</code>class provides a set of instances and static methods to manipulate the response data
            </p>
            <ul>
                <li><code>setStatusCode(value[, text])</code>Set the http status code</li>
                <li><code>setHeader(name, value)</code>Set the header</li>
                <li><code>setContent(content)</code>Set the entity content</li>
                <li><code>setCookie(name, value[, options])</code>Set a cookie</li>
                <li><code>send([content])</code>Send an HTTP response to the client</li>
                <li><code>redirect(url[, statusCode = 302])</code>Page redirection</li>
            </ul>

            <h6><b>Use the Response to output data</b></h6>
<p>
<pre><code>
var Response = Candy.include('candy/http/Response');
var response = new Response(res);
response.setContent('some data from server');
response.send();
</code></pre>
</p>

            <h6><b>Use the Response to redirection</b></h6>
<p>
<pre><code>
var Response = Candy.include('candy/http/Response');
var response = new Response(res);
response.redirect('http://foo.com');
</code></pre>
</p>

            <h1 class="page-header" id="helper"><b>Assistant class</b></h1>
            <p>The assistant class encapsulates some common operations</p>

            <h4><b>File Assistant class<code>FileHelper</code></b></h4>
            <ul>
                <li><code>getDirname(dir)</code></li>
                <li><code>normalizePath(path[, directorySeparator = '/'])</code></li>
                <li><code>createDirectory(dir[, mode = 0o777[, callback = null]])</code></li>
                <li><code>createDirectorySync(dir[, mode = 0o777])</code></li>
            </ul>

            <h4><b>String helper class<code>StringHelper</code></b></h4>
            <ul>
                <li><code>nIndexOf(str, find, n)</code>Find the position where a string appears at the Nth occurrence in another string</li>
                <li><code>trimChar(str, character)</code></li>
                <li><code>lTrimChar(str, character)</code></li>
                <li><code>rTrimChar(str, character)</code></li>
                <li><code>ucFirst(str)</code></li>
                <li><code>htmlSpecialChars(str[, flag = 0[, doubleEncode = true]])</code></li>
                <li><code>filterTags(str[, allowed = ''])</code>Filter html tags</li>
            </ul>

            <h4><b>Time Assistant class<code>TimeHelper</code></b></h4>
            <ul>
                <li><code>format(formats[, timestamp = Date.now()])</code></li>
            </ul>

<p>
<pre><code>
var Response = Candy.include('candy/helpers/FileHelper');
var Response = Candy.include('candy/helpers/StringHelper');
var Response = Candy.include('candy/helpers/TimeHelper');

// return /a/c
var path = FileHelper.normalizePath('/a/./b/../c');

// return &amp;lt;script&amp;gt;
var str = StringHelper.htmlSpecialChars('&lt;script&gt;');

// return abcxyz
var strTag = StringHelper.filterTags('&lt;a&gt;abc&lt;/a&gt;xyz');

// return xxxx-xx-xx xx:xx:xx
var time = TimeHelper.format('y-m-d h:i:s');
</code></pre>
</p>

            <h1 class="page-header" id="alias"><b>Alias ​​system</b></h1>
            <p><code>CandyJs</code>provides a alias system</p>
            <p>An alias is a string beginning with an<code>@</code>sign. Each alias corresponds to a real physical path</p>
            <p>In<code>CandyJs</code>either create class or load class used alias</p>

            <h4><b>System built-in alias</b></h4>
            <ul>
                <li><code>@candy</code>Points to the CandyJs directory</li>
                <li><code>@app</code>Project directory</li>
                <li><code>@runtime</code>Cache directory</li>
                <li><code>@root</code>Website root directory</li>
            </ul>

            <h4><b>Custom alias</b></h4>
            <p>Users can customize aliases</p>
<p>
<pre><code>
// register alias
Candy.setPathAlias('@lib', '/home/www/library');

// create /home/www/library/MyClass class instance
var obj = Candy.createObject('lib/MyClass');
</code></pre>
</p>

            <h1 class="page-header" id="restful"><b>RESTful</b></h1>
            <blockquote class="bg-danger">
                This function was experimental before 4.0.0
            </blockquote>

            <h4><b>Usage</b></h4>
            <ul>
                <li><code>get(route, handler)</code></li>
                <li><code>post(route, handler)</code></li>
                <li><code>put(route, handler)</code></li>
                <li><code>delete(route, handler)</code></li>
                <li><code>patch(route, handler)</code></li>
                <li><code>head(route, handler)</code></li>
                <li><code>options(route, handler)</code></li>
            </ul>
<p>
<pre><code>
var CandyJs = require('candyjs');
var App = require('candyjs/rest/Application');

var app = new App({
    id: 1,
    appPath: __dirname + '/app',
    debug: true
});

// simple get
app.get('/homepage', (req, res) => {
    res.end('homepage');
});

// get with params
app.get('/posts/{id}', (req, res, params) => {
    res.end(params.id);
});

// limit param type
app.get('/user/{id:\\d+}', (req, res, params) => {
    res.end(params.id);
});

// process request with a class
// the code below means /xyz req will process with new Demo().index method
app.get('/xyz', 'app/api/Demo@index');

var candyJs = new CandyJs(app);
candyJs.listen('2333', () => {
    console.log('listen on 2333')
});
</code></pre>
</p>

            <h4><b>Routing issues in RESTful patterns</b></h4>
            <p>
                The routes in RESTful are implemented using regular expressions. It can achieve very flexible routing configuration
                However, the routing performance is poor relative to MVC. ( Routing in the MVC pattern is not implemented in regular expressions. )
            </p>

            <h1 class="page-header" id="log"><b>Log</b></h1>
            <p>
                <code>CandyJs</code>provides the ability to log processing but currently only supports file logs
            </p>

            <h4><b>Use the log</b></h4>
            <p>Before using the log, you need to register in entry file</p>
<p>
<pre><code>
'log': {
    'targets': {
        'file': {
            'classPath': 'candy/log/file/Target',
            'logPath': __dirname + '/logs',
            'logFile': 'system.log',
            'maxFileSize': 10240  // 10 MB
        }
    },
    'flushInterval': 10  // flush to disk every 10 times
}
</code></pre>
</p>

            <h4><b>Log interface</b></h4>
            <ul>
                <li><code>error(message)</code></li>
                <li><code>warning(message)</code></li>
                <li><code>info(message)</code></li>
                <li><code>trace(message)</code></li>
                <li><code>flush()</code></li>
            </ul>
<p>
<pre><code>
var CandyJs = require('candyjs');

var log = CandyJs.getLogger();
log.error('This is a error message');
log.flush();  // flush data to disk
</code></pre>
</p>

            <h1 class="page-header" id="cache"><b>Cache</b></h1>
            <p>
                <code>CandyJs</code>provides the ability to cache data processing but currently only supports file caching
            </p>

            <h4><b>Use caching</b></h4>
            <p>Before using the cache, you need to register in entry file</p>
<p>
<pre><code>
'cache': {
    'file': {
        'classPath': 'candy/cache/file/Target',
        'cachePath': '...'
    }
}
</code></pre>
</p>

            <h4><b>Cache interface</b></h4>
            <ul>
                <li><code>setSync(key, value, duration)</code></li>
                <li><code>set(key, value, duration, callback)</code></li>
                <li><code>getSync(key)</code></li>
                <li><code>get(key, callback)</code></li>
                <li><code>deleteSync(key)</code></li>
                <li><code>delete(key, callback)</code></li>
            </ul>
<p>
<pre><code>
var Candy = require('candyjs/Candy');
var Cache = Candy.include('candy/cache/Cache');

var c = Cache.getCache('file');

// 同步
c.setSync('key', 'value');
var data = c.getSync('key');

// 异步
c.set('key2', 'value2', undefined, (err) => {
    c.get('sync', (err, data) => {
        res.end(data);
    });
});
</code></pre>
</p>

            <h1 class="page-header" id="i18n"><b>I18N</b></h1>
            <blockquote class="bg-info">
                <p>demo <a target="_blank" href="https://github.com/douyu-beijing/candyjs-examples/tree/master/action-filter">see here for detail</a></p>
            </blockquote>

            <h1 class="page-header" id="exception"><b>Exception</b></h1>
            <p><code>CandyJs</code>provide the ability to handle exception, you can implement the<code>candy/web/ExceptionHandler</code>class and override the<code>handlerException()</code>method to output custom message, or you can define a custom class with a<code>handlerException()</code>method</p>
<pre><code>
// index.js
const app = new App({
    'id': 1,
    'appPath': __dirname + '/app',
    // exception handler class
    'exceptionHandler': 'app/ExceptionHandler'
});

// app/ExceptionHandler.js
module.exports = class ExceptionHandler {
    handlerException(res, exp) {
        res.end('server error');
    }
}
</code></pre>

            <h1 class="page-header" id="uploader"><b>FileUploader</b></h1>
            <blockquote class="bg-info">
                <code>CandyJs</code>provides<code>@candyjs/uploader</code>component to implement file upload. <a target="_blank" href="https://github.com/douyu-beijing/candyjs-uploader">view detail</a>
            </blockquote>
            
            <h1 class="page-header" id="database"><b>Database</b></h1>
            <ul>
                <li><a target="_blank" href="https://www.npmjs.com/package/@candyjs/db-mysql2">MYSQL</a></li>
                <li><a target="_blank" href="https://www.npmjs.com/package/@candyjs/db-sqlite3">SQLite</a></li>
            </ul>
            
            <h1 class="page-header" id="ts"><b>TypeScript</b></h1>
            <p>TypeScript is a strongly typed programming language</p>
            <p>
                <code>CandyJs</code>同样支持 typescript 项目以及使用 `tsc` 命令编译项目，但是需要安装<code>@candyjs/tswrapper</code>模块
            </p>
            <p>参考<a href="https://gitee.com/candyjs/candyjs-examples" target="_blank">https://gitee.com/candyjs/candyjs-examples</a>这里的 ts-* 或者 typescript 目录示例</p>
            
            <p>或者参考<a href="https://github.com/candyframework/candyjs-examples" target="_blank">https://github.com/candyframework/candyjs-examples</a>这里的 ts-* 或者 typescript 目录示例</p>

        </div>
        <div class="col-md-3" style="position: relative">
            <ul id="rightnav" class="nav nav-pills nav-stacked" style="background-color: #f5f5f5">
                <li><a href="javascript:;">Getting started</a></li>
                <li><a href="#firstrun">First saying hello</a></li>
                <li><a href="#appstruct">Application structure</a></li>
                <li><a href="#controller">Controller</a></li>
                <li><a href="#routers">Routers</a></li>
                <li><a href="#model">Model</a></li>
                <li><a href="#view">View</a></li>
                <li><a href="#module">Module</a></li>
                <li><a href="#component">Component & Behavior</a></li>
                <li><a href="#midware">Midware</a></li>
                <li><a href="#static">Resource</a></li>
                <li><a href="#url">URI & URL</a></li>
                <li><a href="#reqres">Request & Response</a></li>
                <li><a href="#helper">Helpers</a></li>
                <li><a href="#alias">Alias</a></li>
                <li><a href="#restful">RESTful</a></li>
                <li><a href="#log">Log</a></li>
                <li><a href="#cache">Cache</a></li>
                <li><a href="#i18n">I18N</a></li>
                <li><a href="#exception">Exception</a></li>
                <li><a href="#uploader">FileUpload</a></li>
                <li><a href="#database">Database</a></li>
                <li><a href="#ts">TypeScript</a></li>
            </ul>
        </div>
    </div>
</div>

<footer>
    <div class="container">
        <h4>&copy; CandyJs</h4>
    </div>
</footer>

<script src="./js.js"></script>
</body>
</html>
